home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 09 - 1993 / 09.06 Jun 93 / Programmers' Challenge / Rotate.c.steve < prev   
Encoding:
Text File  |  1993-04-12  |  5.7 KB  |  183 lines  |  [TEXT/KAHL]

  1. /*-------------------------------------------------
  2.  Steve Israelson
  3.  Motion Works Corp.
  4. -------------------------------------------------*/
  5. void RotateBitMapClockwise(BitMap *, BitMap *);
  6. void rotateBlock(unsigned long *,unsigned char *,
  7.     long,unsigned char *,long);
  8. void rotateLimitedBlock(unsigned long *,
  9.     unsigned char *, long,unsigned char *,long,
  10.     short);
  11.  
  12.  
  13. /*-------------------------------------------------
  14.  Rotate the bitmap from src to dst by +90 degrees.
  15.  Make a table for use in the rotate block routine.
  16.  Step through the src in 8x8 blocks, starting from
  17.  the bottom left. Step through dst in 8x8 blocks,
  18.  starting from the top left. Handle the right edge
  19.  of the bitmap specially to prevent bits from being
  20.  rotated into memory outside of the destination.
  21. -------------------------------------------------*/
  22. void RotateBitMapClockwise(BitMap *src, BitMap *dst)
  23. {
  24.     unsigned long    table[16] =
  25.     {0x00000000, 0x00000001, 0x00000100, 0x00000101,
  26.      0x00010000, 0x00010001, 0x00010100, 0x00010101,
  27.      0x01000000, 0x01000001, 0x01000100, 0x01000101,
  28.      0x01010000, 0x01010001, 0x01010100, 0x01010101};
  29.     /* x,y co-ord of source block */
  30.     register short        srcX, srcY;
  31.     /* row bytes, dereferenced for speed */
  32.     short                srcRowBytes, dstRowBytes;
  33.     /* src rowbytes * 8, for speed */
  34.     short                srcRowX8;
  35.     /* width and height of src */
  36.     short                srcWidth, srcHeight;
  37.     /* pointer to src and dst 8x8 blocks */
  38.     char                *srcData, *dstData;
  39.     /* pointer to bitmaps de-referenced for speed */
  40.     char                *srcAddr, *dstAddr;
  41.     /* last few pixels to do specially */
  42.     short                remainder;
  43.     /* a constant, pre-calculated for speed */
  44.     char                *const1;
  45.     
  46.     /* de-reference some constants */
  47.     srcRowBytes = src->rowBytes;
  48.     dstRowBytes = dst->rowBytes;
  49.     srcAddr = src->baseAddr;
  50.     dstAddr = dst->baseAddr;
  51.     
  52.     /* calculate some values */
  53.     srcWidth = src->bounds.right - src->bounds.left;
  54.     srcHeight = src->bounds.bottom - src->bounds.top;
  55.     
  56.     srcRowX8 = srcRowBytes * 8;
  57.     const1 = srcAddr + (srcHeight - 8) * srcRowBytes;
  58.     
  59.     /* loop through the source doing vertical
  60.      * slices starting at the left */
  61.     for (srcX = 0; srcX < srcWidth - 7; srcX += 8) {
  62.         /* bottom edge */
  63.         srcData = const1 + srcX / 8;
  64.         /* left edge */
  65.         dstData = dstAddr + srcX * dstRowBytes;
  66.         for (srcY = srcHeight - 1; srcY >= 0;
  67.           srcY -= 8 ) {
  68.             rotateBlock(table, (unsigned char *)srcData,
  69.                 srcRowBytes, (unsigned char *)dstData,
  70.                 dstRowBytes);
  71.             srcData -= srcRowX8; /* next vert block */
  72.             ++dstData; /* next horiz block */
  73.         }
  74.     }
  75.         
  76.     /* handle the last partial row by calling
  77.      * rotateLimitedBlock() */
  78.     if (remainder = (srcWidth % 8)) {
  79.         /* bottom edge */
  80.         srcData = const1 + srcX / 8; 
  81.         /* left edge */
  82.         dstData = dstAddr + srcX * dstRowBytes;
  83.         for (srcY = srcHeight - 1; srcY >= 0;
  84.           srcY -= 8 ) {
  85.             rotateLimitedBlock(table,
  86.                 (unsigned char *)srcData, srcRowBytes, 
  87.                 (unsigned char *)dstData, dstRowBytes,
  88.                 remainder);
  89.             srcData -= srcRowX8;
  90.             ++dstData;
  91.         }
  92.     }
  93. }
  94.  
  95. /*-------------------------------------------------
  96.  Rotate an 8x8 block of pixels by treating the
  97.  destination block as 2 unsigned longs (64 bits!)
  98.  and using a lookup table to get a mask for the 
  99.  value of each row in the src block.  The table
  100.  essentially stretches out the source byte to 8
  101.  times its size and then ORs it into the
  102.  destination 64bits.  Since the bits are in the
  103.  low bit of each byte, the destination has to be
  104.  shifted one position to the left before each OR
  105.  operation. The offset values are the difference
  106.  in bytes between each row of pixels, equivalent
  107.  to rowBytes. If we had a 64bit data type, this
  108.  would be easier.
  109. -------------------------------------------------*/
  110. void rotateBlock(unsigned long *table,
  111.     unsigned char *src, long srcOffset, 
  112.     unsigned char *dst, long dstOffset)
  113. {
  114.     register unsigned long    resultLO, resultHi;
  115.     short                    x;
  116.     
  117.     resultLO = resultHi = 0;
  118.     src += srcOffset * 7;
  119.     /* compute the rotated result */
  120.     for (x = 0; x < 8; ++x) {
  121.         resultLO = resultLO << 1;
  122.         resultHi = resultHi << 1;
  123.         resultLO |= table[(*src) >> 4];
  124.         resultHi |= table[(*src) & 0x0F];
  125.         src -= srcOffset;
  126.     }
  127.     
  128.     /* store the rotated result */
  129.     *dst = (resultLO & 0xFF000000) >> 24;
  130.     dst += dstOffset;
  131.     *dst = (resultLO & 0x00FF0000) >> 16;
  132.     dst += dstOffset;
  133.     *dst = (resultLO & 0x0000FF00) >> 8;
  134.     dst += dstOffset;
  135.     *dst = resultLO & 0x000000FF;
  136.     dst += dstOffset;
  137.     *dst = (resultHi & 0xFF000000) >> 24;
  138.     dst += dstOffset;
  139.     *dst = (resultHi & 0x00FF0000) >> 16;
  140.     dst += dstOffset;
  141.     *dst = (resultHi & 0x0000FF00) >> 8;
  142.     dst += dstOffset;
  143.     *dst = resultHi & 0x000000FF;
  144. }
  145.  
  146. /*-------------------------------------------------
  147.  Same as other rotateBlock, except will do a
  148.  partial block. Useful to prevent the overwriting
  149.  of memory outside the bitmap!
  150. -------------------------------------------------*/
  151. void rotateLimitedBlock(unsigned long *table,
  152.     unsigned char *src, long srcOffset, 
  153.     unsigned char *dst, long dstOffset, short lines)
  154. {
  155.     register unsigned long    resultLO, resultHi;
  156.     short                    x;
  157.     
  158.     resultLO = resultHi = 0;
  159.     src += srcOffset * 7;
  160.     for (x = 0; x < 8; ++x) {
  161.         resultLO = resultLO << 1;
  162.         resultHi = resultHi << 1;
  163.         resultLO |= table[(*src) >> 4];
  164.         resultHi |= table[(*src) & 0x0F];
  165.         src -= srcOffset;
  166.     }
  167.     *dst = (resultLO & 0xFF000000) >> 24;
  168.     dst += dstOffset; if (lines == 1) return;
  169.     *dst = (resultLO & 0x00FF0000) >> 16;
  170.     dst += dstOffset; if (lines == 2) return;
  171.     *dst = (resultLO & 0x0000FF00) >> 8;
  172.     dst += dstOffset; if (lines == 3) return;
  173.     *dst = resultLO & 0x000000FF;
  174.     dst += dstOffset; if (lines == 4) return;
  175.     *dst = (resultHi & 0xFF000000) >> 24;
  176.     dst += dstOffset; if (lines == 5) return;
  177.     *dst = (resultHi & 0x00FF0000) >> 16;
  178.     dst += dstOffset; if (lines == 6) return;
  179.     *dst = (resultHi & 0x0000FF00) >> 8;
  180.     dst += dstOffset; if (lines == 7) return;
  181.     *dst = resultHi & 0x000000FF;
  182. }
  183.